# @Time : 2024-07-11 14:51
# @Author : Fioman 
# @Phone : 13149920693
"""
摘要
==================================
图形读取 cv2.imread(filename,flags) 读取图像
功能: 从指定的文件路径加载图像并返回该图像的矩阵

参数说明:
filename: 读取的文件路径或者文件名
flags: 可选参数,默认值为1,彩色图像
IMREAD_UNCHANGED:按照原样返回加载的图像(会读取到alpha通道,如果有的话)alpha通道,其实就是这个这个通道是透明还是不
透明的,0表示全透明,白色255表示不透明,灰色表示半透明.下面做了透明的和不透明的试验,需要注意的点就是,opencv的cv2.imshow
函数显示不出来图像的透明性,要使用maplotlib才能显示出来透明度
IMREAD_COLOR: 始终将图像转换为3通道BGR彩色图像,默认的方式.
IMREAD_GRAYSCALE: 转换为灰度图像,单通道的灰度图像.采用的是内部灰度转换功能,它和cvtColor()转换的结果可能不同
IMREAD_ANYDEPTH: 在输入16/32位深度时返回其对应深度的图像,否则就是返回8位深度图像
IMREAD_ANYCOLOR: 尝试以任何可能的颜色格式读取图像,就是如果图像是灰度图像,将会按照灰度图像读取,如果是彩色图像,会
按照彩色读取方式,如果是透明图像(例如PNG图像),会保留它的Alpha通道

注意事项:
1) opencv读取图像不会报错,如果图像不存在或者图像的路径含有中文,将返回None.
2) opencv的彩色图像的格式为BGR格式,而PIL,Pysq,matplotlib等库使用的是RGB格式
3) filename路径不支持中文,如果非要读取中文路径的图像,可以使用cv.imdecode()

cv2.imwrite(filename, img, params=None)
参数说明:
1) filename: 要保存的文件的全路径,包括扩展名,如果没有扩展名或者路径错误,将报错
2) img: 要保存的opencv图像,Numpy array
3) params: 可选参数,不同编码格式的参数,比如:
- CV_IMWRITE_JPEG_QUALITY: 设置.jpeg/.jpg格式的图片质量,取值为0-100(默认是95),数值越大,则图片质量越高.
- CV_IMWRITE_WEBP_QUALITY: 设置.webp格式的图片质量,取值为0-100
- V_IMWRITE_PNG_COMPRESSION: 设置.png格式图片的压缩比,取值为0-9(默认是3),数值越大则压缩比越大.
返回值:
保存成功返回True,否则返回False,后面后缀名不支持,则报错,出现异常

cv2.imdecode(buf,flags)
"""

import os

import cv2
import matplotlib.pyplot as plt
import numpy as np

from settings import IMAGE_PATH


def display_image_use_plt(img, title):
    """
    使用plt显示图像
    :param img:要显示的图像
    :param title:要显示的图像标题
    :return:
    """
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA))
    plt.title(title)
    plt.axis("off")
    plt.show()


imagePath = os.path.join(IMAGE_PATH, "lena.jpg")
image = cv2.imread(imagePath, cv2.IMREAD_UNCHANGED)
# 虽然读取的方式是IMREAD_UNCHANGED但是实际上这个图像是不带透明通道的,所以种类返回的是(x,y,3)
print("Image.shape: {}".format(image.shape))

# 现在我要给它增加一个通道,让其变成一个带有透明通道的图像
height, width = image.shape[:2]
# 完全不透明的通道
alphaChannel01 = np.ones((height, width), dtype=np.uint8) * 255  # 完全不透明,原图显示
alphaChannel02 = np.ones((height, width), dtype=np.uint8) * 128  # 半透明
alphaChannel03 = np.zeros((height, width), dtype=np.uint8)  # 完全透明,纯白色
imageAlpha01 = cv2.merge((image, alphaChannel01))
imageAlpha02 = cv2.merge((image, alphaChannel02))
imageAlpha03 = cv2.merge((image, alphaChannel03))

print("imageAlpha01.shape: {}".format(imageAlpha01.shape))
print("imageAlpha02.shape: {}".format(imageAlpha02.shape))
print("imageAlpha03.shape: {}".format(imageAlpha03.shape))
print("imageAlpha03: {}".format(imageAlpha03))

cv2.imshow("imageAlpha01", imageAlpha01)
cv2.imshow("imageAlpha02", imageAlpha02)
cv2.imshow("imageAlpha03", imageAlpha03)
cv2.waitKey()

display_image_use_plt(imageAlpha01, "notAlpha")
display_image_use_plt(imageAlpha02, "halfAlpha")
display_image_use_plt(imageAlpha03, "fullAlpha")

nullPath = ""
retVal = cv2.imread(nullPath, cv2.IMREAD_ANYCOLOR)
print("空目录读取: retVal = {}".format(retVal))

# 读取中文目录
chinesePath = r"D:\2024\切线图\1.bmp"
# 先判断路径是否存在
if os.path.exists(chinesePath):
    print("中文路径存在")
    retvl = cv2.imread(chinesePath, cv2.IMREAD_ANYCOLOR)
    print("中文路径读取: retVal = {}".format(retvl))
else:
    print("中文路径不存在")

# 直接读取灰度图像和使用cv2.cvtColor转换的灰度图像的灰度值是否相同呢,试验一下
readGray = cv2.imread(imagePath, cv2.IMREAD_GRAYSCALE)
readColor = cv2.imread(imagePath, cv2.IMREAD_COLOR)
converterGray = cv2.cvtColor(readColor, cv2.COLOR_BGR2GRAY)
print("readGray: {}".format(readGray))
print("converterGray: {}".format(converterGray))
isEqual = np.array_equal(readGray, converterGray)
if isEqual:
    print("直接灰度读取和灰度转换后图像像素一致")
else:
    print("直接灰度读取和灰度转换后图像像素不一致")

difference = readGray != converterGray
difNum = np.sum(difference)
print("不一致的个数: {}".format(difNum))
differenceIndices = np.argwhere(difference)
for index in differenceIndices:
    print(index)
# 验证了一下,这个点的坐标就是不一样的,但是差异很小.
x, y = 50, 443
print("readGray: {},converterGray: {}".format(readGray[x, y], converterGray[x, y]))

# 读取中文路径的方式: 采用imdecode的方式,参数是np.fromfile(filePath,dtype=np.uint8)
imageChinesePath = cv2.imdecode(np.fromfile(chinesePath, dtype=np.uint8), cv2.IMREAD_GRAYSCALE)
print("中文目录的读取方式: {}".format(imageChinesePath.shape))

try:
    # 文件路径正确的返回值
    fileSavePath01 = os.path.join(IMAGE_PATH, "test.png")
    retVal = cv2.imwrite(fileSavePath01, image)
    print("文件路径正确的返回值: {}".format(retVal))
except Exception as e:
    print(" error: {}".format(str(e)))

try:
    # 文件路径不正确的返回值
    fileSavePath02 = os.path.join("X", "test.png")
    retVal = cv2.imwrite(fileSavePath02, image)
    print("文件路径不正确的返回值: {}".format(retVal))
except Exception as e:
    print(" error: {}".format(str(e)))

try:
    # 文件路径有中文的时候的返回值
    fileSavePath03 = os.path.join(r"D:\2024\切线图", "test.png")
    print("fileSavePath03 = {}".format(fileSavePath03))
    retVal = cv2.imwrite(fileSavePath03, image)
    print("文件路径存在,但是有中文的时候的返回值: {}".format(retVal))
except Exception as e:
    print(" error: {}".format(str(e)))

# 具有中文路径的时候发现保存图像没有出现异常,但是出现了乱码,并且将切线图\test当成了文件名的一部分了
# 就是说中文目录咋子cv2.imwrite()这个函数中是识别不了的,也就是说保存图像的时候最好不要使用中文

try:
    # 文件路径的扩展名不支持的时候,会报异常
    fileSavePath04 = os.path.join(IMAGE_PATH, "a.abc")
    retVal = cv2.imwrite(fileSavePath04, image)
    print("文件路径的扩展名不支持的时候的返回值: {}".format(retVal))
except Exception as e:
    print(" error: {}".format(str(e)))

# 中文目录图像读取和保存,并且图像压缩问题,我们可以获取一个文件的原始大小就是字节数,然后保存完之后再获取一次
imageOriginal = cv2.imdecode(np.fromfile(chinesePath, dtype=np.uint8), cv2.IMREAD_COLOR)
originalSize = os.path.getsize(chinesePath) / (1024 * 1024)
print("原始文件大小: {:.2f} Mb".format(originalSize))
chinesePath02 = r"D:\2024\切线图\2.jpg"
cv2.imencode(".jpg", imageOriginal)[1].tofile(chinesePath02)
newSize = os.path.getsize(chinesePath02) / (1024 * 1024)
print("保存为jpg之后的文件大小: {:.2f} Mb".format(newSize))

# 保存为png格式图像
chinesePath03 = r"D:\2024\切线图\3.png"
# 可以设置压缩比例,从0~9 ,默认是3,压缩等级为0就是不压缩,等级越高,压缩的比例越高,质量越差
cv2.imencode(".png", imageOriginal, [cv2.IMWRITE_PNG_COMPRESSION, 0])[1].tofile(
    chinesePath03)
newSize = os.path.getsize(chinesePath03) / (1024 * 1024)
print("压缩等级为0的文件大小: {:.2f} Mb".format(newSize))

chinesePath04 = r"D:\2024\切线图\4.png"
cv2.imencode(".png", imageOriginal, [cv2.IMWRITE_PNG_COMPRESSION, 9])[1].tofile(
    chinesePath04)
newSize = os.path.getsize(chinesePath04) / (1024 * 1024)
print("压缩等级为9的文件大小: {:.2f} Mb".format(newSize))
